package titan.utils;

import java.io.File;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.xpath.XPath;
import javax.xml.xpath.XPathConstants;
import javax.xml.xpath.XPathFactory;
import org.w3c.dom.Document;
import org.w3c.dom.NamedNodeMap;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import titan.messages.Messages;

/**
 * Class XMLReader.
 * Given a XML document, this class allows to obtain its elements by the name 
 * as well as the values of its attributes
 */
public class XMLReader {
	private Document doc;
	private String xml;

	/**
	 * Saves the given file path and calls the parse method
	 * @param xmlPath - the path of the xml file
	 * @throws Exception if it can't open the xml file
	 */
	public XMLReader(String xmlPath) throws Exception{
		xml = xmlPath;
		parse(null, xmlPath);
	}

	/**
	 * Saves the absolute path of the given file and calls the parse method
	 * @param xmlFile - the xml file reference
	 * @throws Exception if it can't open the xml file
	 */
	public XMLReader(File xmlFile) throws Exception{
		xml = xmlFile.getAbsolutePath();
		parse(xmlFile, null);
	}

	/**
	 * Parses a xml file. The file reference or a path to the file can be given
	 * @param xmlFile - the xml file reference
	 * @param xmlPath - the xml path
	 * @throws Exception if it can't open the xml file
	 */
	private void parse(File xmlFile, String xmlPath) throws Exception{
		try{
	        DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
			DocumentBuilder docBuilder = factory.newDocumentBuilder();
			if(xmlFile == null)
				doc = docBuilder.parse(xmlPath); //$NON-NLS-1$
			else
				doc = docBuilder.parse(xmlFile); //$NON-NLS-1$
		} catch(Exception e) {
			throw new Exception(Messages.UnableRead+xml);
		}
	}

	/**
	 * Gets a list of elements by the tag name
	 * @param tagName - the tag name
	 * @return NodeList - a list of elements with the tag name
	 * @throws Exception if no node was found
	 */
	public NodeList getElementsByTagName(String tagName) throws Exception{
		NodeList nl = doc.getElementsByTagName(tagName);
		testNodeList(nl, tagName);
		return nl;
	}

	/**
	 * Gets a node in a node map by name and put your value into a String
	 * @param attribs - the node map where the node is
	 * @param itemName - the node name
	 * @return String - the value of the node
	 * @throws Exception if it can't find the node
	 */
	public static String getNodeValue(NamedNodeMap attribs, String itemName) throws Exception{
			Node attrib = attribs.getNamedItem(itemName); //$NON-NLS-1$
			if(attrib == null)
				throw new Exception(Messages.NodeNFound+itemName);
			return attrib.getNodeValue();
	}

	/**
	 * Gets the children of a node by the tag name
	 * @param tagName - the tag name
	 * @param node - the node to get children
	 * @return NodeList - list with nodes that are children of the given node
	 * @throws Exception if no child was found
	 */
	public static NodeList getChildrenByTagName(String tagName, Node node) throws Exception{
		XPathFactory xpathFactory = XPathFactory.newInstance();
		XPath xpath = xpathFactory.newXPath();
		NodeList nl = (NodeList) xpath.evaluate(tagName, node, XPathConstants.NODESET);
		testNodeList(nl, tagName);
		return nl; //$NON-NLS-1$
	}

	/**
	 * Verifies if the node list is not empty
	 * @param nl - the list of nodes
	 * @param tagName - the tag name that had to be in the list
	 * @throws Exception if the node list is empty
	 */
	public static void testNodeList(NodeList nl, String tagName) throws Exception{
		if(nl == null || nl.getLength() < 1)
			throw new Exception(Messages.ElementNFound+tagName);
	}
}
